# -*- coding: utf-8 -*-
# coding:utf-8

import time
import base
import Queue
import logging
import threading
import Levenshtein
__author__ = 'lancelrq'


class ContestCodeAnalysis(base.Base):

    def __init__(self, contest_id, ignore_problem_list):
        base.Base.__init__(self, 'Contest_Code_Analysis')
        self.__API_GET_CODE_ANALYSIS_LIST = 'http://'+ self._const.BASE_HOSTNAME +'/datacenter/contest/%s/get_code_analysis_list' % contest_id
        self.__API_GET_JUDGE_STATUS = 'http://'+ self._const.BASE_HOSTNAME +'/datacenter/contest/%s/get_status_list' % contest_id
        self.__API_RECEIVE_CODE_CHECK_RESULT = 'http://'+ self._const.BASE_HOSTNAME +'/datacenter/contest/%s/problem/%s/receive_code_check_result'
        # ===========
        self.__result_list = self.wejudge_api_call(self.__API_GET_CODE_ANALYSIS_LIST)
        if self.__result_list is False or self.__result_list is None:
            self.log(u"数据读取失败！意外终止！", None, logging.ERROR)
            raise Exception("数据读取失败！意外终止！")
        self.__judge_status = {}
        self.__status_queue = Queue.Queue()
        self.__timestamp = 0
        self.__contest_id = contest_id
        self.__ignore_problem_list = ignore_problem_list
        self.__gs_thread = threading.Thread(target=self.__get_status_worker)
        self.__pc_thread = threading.Thread(target=self.__proc_worker)
        # ===========
        self.log(u"比赛服代码查重分析模块初始化完成")

    def start(self):
        """
        启动工作线程
        :return:
        """
        self.__gs_thread.setDaemon(True)
        self.__gs_thread.start()
        self.__pc_thread.setDaemon(True)
        self.__pc_thread.start()


    def __get_status_worker(self):
        """
        这个线程是用来读取评测记录的，按5秒钟取一次
        :return:
        """
        while True:
            status_list = self.wejudge_api_call(self.__API_GET_JUDGE_STATUS, {'timestamp': self.__timestamp})
            if status_list is not False:
                for status in status_list:
                    self.__status_queue.put(status)
                    self.__status_queue.task_done()
                    if status.get('timestamp', 0) > self.__timestamp:
                        self.__timestamp = status.get('timestamp', 0)
                if len(status_list) > 0:
                    self.log(u"取得%s项评测记录数据" % len(status_list), 'Contest_Code_Analysis_SW')

            time.sleep(5)


    def __proc_worker(self):
        """
        查重处理程序
        :return:
        """
        while True:
            status1 = self.__status_queue.get(block=True)        # 从队列中获取一个评测记录
            problem_id = unicode(status1.get('problem_id', None))
            if unicode(problem_id) in self.__ignore_problem_list:
                continue
            if problem_id is not None:
                pjs = self.__judge_status.get(problem_id, [])       # 读取相同问题的评测记录
                prl = self.__result_list.get(problem_id, {})
                pjs.append(status1)
                self.__judge_status[problem_id] = pjs
                if len(pjs) > 0:
                    for status2 in pjs:
                        if status1.get('author_id', '') == status2.get('author_id', ''):  # 自己的评测记录可以直接无视
                            continue
                        k1 = u"%s-%s" % (status1.get('id', ''),status2.get('id', ''))
                        k2 = u"%s-%s" % (status2.get('id', ''),status1.get('id', ''))
                        if prl.has_key(k1) or prl.has_key(k2):
                            exist = True
                        else:
                            exist = False
                        if not exist:       # 如果没有处理过
                            # 读取status1对应的代码
                            fs = open("%s/%s" %(self._const.USER_UPLOADCODE_DIR, status1.get('code_path', '')), 'r')
                            code1 = fs.read().replace('\n', '').replace('\r', '').replace('\t', '').replace('\n', '')
                            fs.close()
                            # 读取status2对应的代码
                            fs = open("%s/%s" %(self._const.USER_UPLOADCODE_DIR, status2.get('code_path', '')), 'r')
                            code2 = fs.read().replace('\n', '').replace('\r', '').replace('\t', '').replace('\n', '')
                            fs.close()
                            # 读取记录
                            ratio = Levenshtein.ratio(code1, code2)
                            if ratio < 0.5:
                                continue
                            flag = self.wejudge_api_call(
                                self.__API_RECEIVE_CODE_CHECK_RESULT % (self.__contest_id, problem_id),
                                {
                                    "status1": status1.get('id'),
                                    "status2": status2.get('id'),
                                    "ratio": ratio
                                }
                            )
                            if flag:
                                self.log(u"查重录入：%s <-> %s: %.3f" % (status1.get('id',''), status2.get('id',''), ratio))
                            else:
                                self.log(u"查重录入：%s <-> %s: %.3f REPORT FAILED" % (status1.get('id',''), status2.get('id',''), ratio),
                                         None, logging.ERROR)
                            prl[k1] = ratio
                            self.__result_list[problem_id] = prl
